package biolabs.gui;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.Closeable;
import java.io.IOException;
import java.util.logging.Level;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

import biolabs.core.Application$;
import biolabs.sink.Sink;

/**
 * {@code WindowSink} is a {@link Sink} that receives and displays
 * visualization data. The visualization can either be shown in its own
 * window (using {@link #show()}/{@link #hide()}), or incorporated as
 * part of another UI layout (using {@link #getContent()} to obtain the
 * UI component containing the visualization).
 *
 * @param <T>
 *
 * @author Tomas Mikula
 */
public abstract class WindowSink<T> implements Sink<T>, UIComponent {

	/**
	 * initial size of the visualization window
	 */
	private static final Dimension SIZE = new Dimension(500, 500);

	private JFrame window;
	private Closeable visualizationHandle;

	private final WindowListener closeVisualizationOnCloseAttempt = new WindowListener() {

		@Override
		public void windowClosing(WindowEvent e) {
			if(visualizationHandle == null)
				throw new IllegalStateException("visualization handle is null");
			try {
				// this will cause a call to the close() method
				visualizationHandle.close();
			} catch(IOException ex) {
				Application$.MODULE$.LOGGER().log(Level.WARNING, "I/O error", ex);
			}
		}

		@Override public void windowActivated(WindowEvent e) {}
		@Override public void windowClosed(WindowEvent e) {}
		@Override public void windowDeactivated(WindowEvent e) {}
		@Override public void windowDeiconified(WindowEvent e) {}
		@Override public void windowIconified(WindowEvent e) {}
		@Override public void windowOpened(WindowEvent e) {}
	};

	private synchronized JFrame getWindow() {
		if(window == null) {
			JPanel panel = new JPanel(new GridLayout(1, 1));
			panel.add(getContent());
			window = new JFrame();
			window.add(panel);
			window.setSize(SIZE);
			window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
			window.addWindowListener(closeVisualizationOnCloseAttempt);
		}
		return window;
	}

	public void setVisualizationHandle(Closeable handle) {
		visualizationHandle = handle;
	}

	public void show() {
		getWindow().setVisible(true);
	}

	public void hide() {
		getWindow().setVisible(false);
	}

	/**
	 * Disposes the window. When overriding,
	 * don't forget to call {@code super.close()}.
	 */
	@Override
	public void close() {
		window.dispose();
	}
}
